
using System;
using System.Reflection;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Drawing;
using System.Xml;

namespace MxitAPI
{
	
	
	public class Utilities
	{
		
		private static log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType );
		
		private const int clientKeyLength = 8;
		private const string initializationKey = "6170383452343567";
        private const string settingsFile = "settings.xml";
		
		public Utilities()
		{
		}
		
		/**
		 * Remove a single row from a jagged string array
		 * @return the new jagged string array without the row at index @rowNumber
		 */
		// Todo Not very efficient. Change this method
		public static string[][] RemoveArrayRow( string[][] array, int rowNumber ) {
			string[][] newArray = new string[array.Length - 1 ][];
			int j = 0;
			for ( int i = 0; i < array.Length; ++i ) {
				if ( i != rowNumber )
					newArray[ j++ ] = array[i];
			}
			
			return newArray;
		}
		
		public static string[] RemoveArrayRow( string[] array, int rowNumber ) {
			string[] newArray = new string[array.Length - 1 ];
			int j = 0;
			for ( int i = 0; i < array.Length; ++i ) {
				if ( i != rowNumber )
					newArray[ j++ ] = array[i];
			}
			
			return newArray;
		}

		/**
		 * Remove multiple rows from a jagged string array
		 * @return the new jagged string array without the rows given in rowIndices[]
		 */
		public static string[][] RemoveArrayRows( string[][] array, int[] rowIndices ) {
			
			// Create a new array with the smaller size
			string[][] newArray = new string[array.Length - rowIndices.Length ][];
			int j = 0;
			bool removeThisRow;
			for ( int i = 0; i < array.Length; ++i ) {
				
				// Check the list of rows to remove to see if the ith row must be removed
				removeThisRow = false;
				for ( int k = 0; k < rowIndices.Length ; ++k ) {
					if ( i == rowIndices[k] ) {
						removeThisRow = true;
						continue;
					}
				}
				
				// If the ith row must not be removed then add it to the array
				if ( !removeThisRow )
					newArray[ j++ ] = array[i];
			}
			
			return newArray;
		}

        public static string ReadApplicationSetting( string userName, string nodeName ){
            XmlTextReader xmlReader = new XmlTextReader( settingsFile );
            string value = string.Empty;

            while ( xmlReader.Read() ) {
                xmlReader.MoveToContent();

                if ( xmlReader.Name == "ApplicationSettings" && xmlReader.NodeType != XmlNodeType.EndElement ) {
                    string xmlUserName = xmlReader.GetAttribute( "username" );

                    // If this user has application settings in the xml file
                    if ( xmlUserName == userName ) {
                        xmlReader.Read();
                        xmlReader.MoveToContent();
                        if ( xmlReader.Name == nodeName ) {
                            value = xmlReader.GetAttribute( "value" );
                            break;
                        }
                    }
                }
            }

            xmlReader.Close();

            return value;   
        }

        public static string ReadApplicationSetting( string nodeName ) {
            return ReadApplicationSetting( ApplicationInfo.Instance.UserName, nodeName );
        }

        public static void WriteApplicationSetting( string userName, string nodeName, string value ) {
            string previousValue = ReadApplicationSetting( userName, nodeName );
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load( settingsFile );
          //  if ( previousValue ) {
            XmlNode rootNode = xmlDoc.SelectSingleNode( "//root" );
            XmlNode settingsNode = xmlDoc.SelectSingleNode( "//*[@username='" + userName + "']" );
            
            if ( settingsNode != null ) {
                foreach ( XmlNode node in settingsNode.ChildNodes ) {
                    if ( node.Name == nodeName ) {
                        settingsNode.RemoveChild( node );
                        break;
                    }
                
                }
            }
            else {
                XmlElement settingsElement = xmlDoc.CreateElement( "ApplicationSettings" );
                settingsElement.SetAttribute( "username", userName );
                settingsNode = settingsElement;
                rootNode.InsertAfter( settingsNode, rootNode.LastChild );
 
            }

            //XmlNode productIdNode = xmlDoc.SelectSingleNode( "//*[@username='" + userName + "']" );
            XmlElement newElement = xmlDoc.CreateElement( nodeName );
            newElement.SetAttribute( "value", value );
            settingsNode.InsertAfter( newElement, settingsNode.LastChild );
            //}
            xmlDoc.Save( settingsFile );
        }

        public static void WriteApplicationSetting( string nodeName, string value ) {
            WriteApplicationSetting( ApplicationInfo.Instance.UserName, nodeName, value );
        }
		
		public static string EncryptPassword( string password ) {
			
			string productId = ApplicationInfo.Instance.ProductId;//"24B2353E81-943B-4EDB-8E6D-697C8B79C9780E91A58C";
			log.DebugFormat( "Initialization key [{0}]", initializationKey  );
			log.DebugFormat( "Product ID [{0}]", productId  );
			
			// Get the client key ( last part ( currently 8 bytes ) of the product id )
			string clientKey = productId.Substring( productId.Length - clientKeyLength );
			log.DebugFormat( "Client key [{0}]", clientKey  );
			
			// Create the encryption key by replacing the first part of the initialization key with the client key
			string encryptionKey = clientKey + initializationKey.Substring( clientKeyLength );
			log.DebugFormat( "Encryption key [{0}]", encryptionKey  );
			
			// The plain text to be encrypted
			string plainText = "<mxit/>" + password;// + "PPPP\u0004";
			log.DebugFormat( "Plain text [{0}]", plainText  );
			
			// Convert strings to byte arrays for encryption
			byte[] encryptionKeyBytes = Encoding.ASCII.GetBytes( encryptionKey );
			byte[] plainTextBytes = Encoding.ASCII.GetBytes( plainText );
			
			RijndaelManaged rijndael = new RijndaelManaged();
			rijndael.Mode = CipherMode.ECB;
			rijndael.BlockSize = 128;
			rijndael.Padding = PaddingMode.ISO10126;
			rijndael.Key = encryptionKeyBytes;
			
			ICryptoTransform encryptor = rijndael.CreateEncryptor();
			MemoryStream memoryStream = new MemoryStream();
			CryptoStream cryptoStream = new CryptoStream( memoryStream, encryptor, CryptoStreamMode.Write );
			
			// Perform the encryption
			cryptoStream.Write( plainTextBytes, 0, plainTextBytes.Length );
			cryptoStream.FlushFinalBlock();
			
			// Get the resultant encrypted bytes
			byte[] cipherTextBytes = memoryStream.ToArray();
			
			memoryStream.Close();
			cryptoStream.Close();
			
			// Convert cipherText to base64 string
			string cipherText = Convert.ToBase64String( cipherTextBytes );
			log.DebugFormat( "Cipher text          [{0}]", cipherText );
			
			
			
			// Decrypt cipherText to check if its right 
			// Todo remove this - debugging only
			//string decryptedPassword = DecryptPassword( cipherText, encryptionKey );
			//log.DebugFormat( "Decrypted cipherText [{0}]", decryptedPassword );
			
			return cipherText;
		}
		
		private string DecryptPassword( string cipherText, string encryptionKey ) {
			
			byte[] encryptionKeyBytes = Encoding.ASCII.GetBytes( encryptionKey );
			byte[] cipherTextBytes = Convert.FromBase64String ( cipherText );

			RijndaelManaged rijndael = new RijndaelManaged();
			rijndael.Mode = CipherMode.ECB;
			//rijndael.BlockSize = 128;
			rijndael.Padding = PaddingMode.ISO10126;
			rijndael.Key = encryptionKeyBytes;
			
			ICryptoTransform decryptor = rijndael.CreateDecryptor();
			MemoryStream memoryStream = new MemoryStream( cipherTextBytes );
			CryptoStream cryptoStream = new CryptoStream( memoryStream, decryptor, CryptoStreamMode.Read );
			
			byte[] plaintTextBytes = new byte[ cipherTextBytes.Length ];
			
			int decryptedByteCount = cryptoStream.Read( plaintTextBytes, 0, plaintTextBytes.Length );
			
			memoryStream.Close();
			cryptoStream.Close();
			
			// Get the plainText as a string
			string plainText = Encoding.UTF8.GetString( plaintTextBytes, 0, decryptedByteCount );
			
			return plainText;
		}


        // http://www.dailycoding.com/Posts/convert_image_to_base64_string_and_base64_string_to_image.aspx
        public static Image Base64ToImage( string base64String ) {
            // Convert Base64 String to byte[]
            byte[] imageBytes = Convert.FromBase64String( base64String );
            MemoryStream ms = new MemoryStream( imageBytes, 0,
              imageBytes.Length );

            // Convert byte[] to Image
            ms.Write( imageBytes, 0, imageBytes.Length );
            Image image = Image.FromStream( ms, true );
            return image;
        }
		
		// Todo Remove this
		/// http://aspalliance.com/778
		public static void DisplayReflectionDetails( Type type) {
  			Console.WriteLine ( "Class: " + type) ;
  			Console.WriteLine ();
  			Console.WriteLine ( "Namespace: " +type.Namespace ) ;
  			Console.WriteLine ();
  			ConstructorInfo[] constructorInfo = 
  			type.GetConstructors( );
  			Console.WriteLine( "Constructors:--") ;
  			foreach( ConstructorInfo c in constructorInfo)
  			{
   				Console.WriteLine( c ) ;
  			}
			 
  			PropertyInfo[] propertyInfo =type.GetProperties( );
  			Console.WriteLine ();
  			Console.WriteLine( "Properties:--" );
  			foreach( PropertyInfo p in propertyInfo ) {
   				Console.WriteLine( p ) ;
  			}
			
  			MethodInfo[] methodInfo = type.GetMethods( ) ;
  			Console.WriteLine ();
  			Console.WriteLine( "Methods:--" ) ;
  			ParameterInfo[] parameterInfo = null;
  			foreach( MethodInfo m in methodInfo ) {
   				Console.WriteLine( "Method Name: "+ m.Name ) ;
   				parameterInfo = m.GetParameters () ;
				foreach ( ParameterInfo p in parameterInfo ) {			
   					Console.WriteLine("Parameter Type:" + p.ParameterType + " Parameter Name: " + p.Name ) ;
   				}	
  			} 
		}
		
	}
}
